package com.buwei.module.rbac.domain.entity;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.experimental.FieldDefaults;

@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
@FieldDefaults(level = AccessLevel.PRIVATE)
@Entity
@EntityListeners(AuditingEntityListener.class)
@Table
public class Role implements Serializable {

	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	Long id;
	
	/**
	 * 角色中文名
	 */
	@NotEmpty
	@Column(length=20)
	String name;
	
	/**
	 * 角色代码或者英文名
	 */
	@NotEmpty
	@Column(length=20)
	String value;

	@JsonIgnore
	@Transient //一方加上，不然还是会创建外键
	@OneToMany(cascade = { CascadeType.ALL }, mappedBy = "role",fetch=FetchType.LAZY)
	Set<User> users;
	
	//废除一对多，采用对多对
	/*
	 * 关系维护端删除时，如果中间表存在些纪录的关联信息，则会删除该关联信息;
	 * 关系被维护端删除时，如果中间表存在些纪录的关联信息，则会删除失败 .
	 */ 
	@ManyToMany(
			targetEntity=Resource.class,
			cascade={CascadeType.REFRESH}, 
			fetch = FetchType.EAGER) //fetch设为lazy发现会在单元测试时加载不到permission
	@JoinTable(//关联表 
			name = "t_role_resource", //关联表名
			joinColumns = @JoinColumn(
					name = "role_id", 
					foreignKey = @ForeignKey(name = "none",value = ConstraintMode.NO_CONSTRAINT)), //维护端外键 
			inverseJoinColumns = @JoinColumn(
					name = "resource_id", 
					foreignKey = @ForeignKey(name = "none",value = ConstraintMode.NO_CONSTRAINT)) //被维护端外键
			 //多方加上
			)
	List<Resource> resources;
	
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+08:00")
	@CreatedDate
    LocalDateTime createdAt;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+08:00")
    @LastModifiedDate
    LocalDateTime editedAt;
    
    
	@Getter
	public enum RoleName {
		系统管理员("ROLE_ADMIN", "系统管理员"), 普通用户("ROLE_USER", "普通用户"), 主管("ROLE_MANAGER", "主管");
		
        private String name;
        private String value;

        private RoleName(String name, String value) {
            this.name = name;
            this.value = value;
        }
	}
}
